package com.ibm.spatiotemp.server.framework.processor.mocking;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.ibm.spatiotemp.server.connections.ConnectionManager;
import com.ibm.spatiotemp.server.datamodel.gpsdata.TSPointResultSet;
import com.ibm.spatiotemp.server.datamodel.gpsdata.mocking.MockingTSPointResutSet;
import com.ibm.spatiotemp.server.datasources.DataSource;
import com.ibm.spatiotemp.server.datasources.QueryStringFormatter;
import com.ibm.spatiotemp.server.datasources.mockdb.MockdbQueryStringFormatter;
import com.ibm.spatiotemp.server.framework.processor.SpatialQueryProcessor;
import com.ibm.spatiotemp.server.framework.reponse.ResponseFormatter;
import com.ibm.spatiotemp.server.framework.request.Request;
import com.ibm.spatiotemp.tools.DateParser;
import com.ibm.spatiotemp.tools.RegionBBox;

public class MockingSpatialQueryProcessor extends SpatialQueryProcessor{
	public static Logger logger1 = Logger.getLogger(MockingSpatialQueryProcessor.class);
	
	private Connection conn;
	private Statement traj_statement;
	private Statement time_statement;
	private Statement pos_statement;
	
	private QueryStringFormatter sqlformatter; 
	
	public MockingSpatialQueryProcessor(DataSource src) {
		super(src);
		sqlformatter = new MockdbQueryStringFormatter();
		try {
			conn = ConnectionManager.GetConnection(src.getConnection_string());
		} catch (SQLException e) {
			logger1.error(e);
		}
	}

	
	/*
	 * 
	 * Query Position by timestamp and bbox: Retrieve the position of all moving objects at a specific time within bbox.
	Method: GET /tenant1?queryType=position&time=2014-01-01T00:00:20&&bbox=[-122.40327,37.52015,-122.3101,37.90572]
	 * */
	@Override
	public String handlePositionQuery(Request request) throws Exception {
		logger1.info(request.toJsonString());
		JsonNode bboxnode = request.getBbox();
		RegionBBox bbox = new RegionBBox(bboxnode);
		
		String timestring = request.getTime();
		long time = DateParser.getTimestamp(timestring);
		
		MockdbQueryStringFormatter formatter = (MockdbQueryStringFormatter)sqlformatter;
		TSPointResultSet resset = null;
		
		if(pos_statement==null){
			pos_statement = (Statement) conn.createStatement();
		}
		String sql = formatter.PositionQueryString(datasource.getDataschema(), time, bbox);
		logger1.info(sql);
		ResultSet resultSet = pos_statement.executeQuery(sql);
		resset = new MockingTSPointResutSet(resultSet);

		String retstring = "[%s]";
		StringBuffer strbuf = new StringBuffer();
		String[] results = ResponseFormatter.formatTSPointResultSetAsPoints(resset);
		int curidx = 0;
		for(curidx = 0; curidx < results.length; ++curidx)
		{
			if(curidx != 0)
			{
				strbuf.append(",");
				strbuf.append(results[curidx]);
			}
			else
				strbuf.append(results[curidx]);
		}
		retstring = String.format(retstring, strbuf.toString());
		
		return retstring;
	}

	@Override
	public String handleTrajectoryQuery(Request request) throws Exception {
		logger1.info(request.toJsonString());
		String retstring = "";
		String modid = request.getId();
		String startts = request.getStartts();
		String endts = request.getEndts();
		JsonNode bboxnode = request.getBbox();
		
		MockdbQueryStringFormatter formatter = (MockdbQueryStringFormatter)sqlformatter;
		TSPointResultSet resset = null;
		
		if(traj_statement==null){
			traj_statement = (Statement) conn.createStatement();
		}
		
		if(bboxnode== null)/*type1 query*/
		{
				long start = DateParser.getTimestamp(startts);
				long  end = DateParser.getTimestamp(endts);
				String sql = formatter.TrajectoryQueryStringType1(datasource.getDataschema(), start, end, modid);
				logger1.info(sql);
				
				ResultSet resultSet = traj_statement.executeQuery(sql);
				resset = new MockingTSPointResutSet(resultSet);
				retstring = ResponseFormatter.formatTSPointResultSetAsTimeandCoordinates(resset)[0];
		}
		else{/*type 2 query*/
			
			long start = DateParser.getTimestamp(startts);
			long  end = DateParser.getTimestamp(endts);
			RegionBBox bbox = new RegionBBox(bboxnode);
			String sql = formatter.TrajectoryQueryStringType2(datasource.getDataschema(), start, end, bbox, modid);
			logger1.info(sql);
			
			ResultSet resultSet = traj_statement.executeQuery(sql);
			resset = new MockingTSPointResutSet(resultSet);

			retstring = "[%s]";
			StringBuffer strbuf = new StringBuffer();
			String[] results = ResponseFormatter.formatTSPointResultSetAsTimeandCoordinates(resset);
			int curidx = 0;
			for(curidx = 0; curidx < results.length; ++curidx)
			{
				if(curidx != 0)
				{
					strbuf.append(",");
					strbuf.append(results[curidx]);
				}
				else
					strbuf.append(results[curidx]);
			}
			retstring = String.format(retstring, strbuf.toString());
		}
		return retstring;
	}

	/*
	 * Query Time by position: Retrieve the first time a moving object is within a specified distance of a position within the given time range.
	 * Method: GET /tenant1?queryType=firsttime&id=uuid1&position=[25,36]&distance=5&start=2014-01-01T00:00:00&end=2014-02-01T00:00:00
	 * */
	@Override
	public String handleTimeQuery(Request request) throws Exception {
		logger1.info(request.toJsonString());
		String modid = request.getId();
		String startts = request.getStartts();
		String endts = request.getEndts();
		JsonNode posjson = request.getPosition();
		
		double center_x = 0;
		double center_y = 0;
		if(posjson instanceof ArrayNode){
			center_x = posjson.get(0).asDouble();
			center_y = posjson.get(1).asDouble();
		}
		else{
			logger1.error("wrong position string:" + posjson.asText());
		}
		
		double dist = request.getDistance();
		RegionBBox bbox = new RegionBBox(center_x,center_y,dist);
		
		long start = DateParser.getTimestamp(startts);
		long  end = DateParser.getTimestamp(endts);
		
		MockdbQueryStringFormatter formatter = (MockdbQueryStringFormatter)sqlformatter;
		TSPointResultSet resset = null;
		
		if(time_statement==null){
			time_statement = (Statement) conn.createStatement();
		}
		String sql = formatter.FirsttimeQueryString(datasource.getDataschema(),modid, start, end, bbox);
		logger.info(sql);
		ResultSet resultSet = time_statement.executeQuery(sql);
		resset = new MockingTSPointResutSet(resultSet);

		String retstring = "[%s]";
		StringBuffer strbuf = new StringBuffer();
		String[] results = ResponseFormatter.formatTSPointResultSetAsPoints(resset);
		int curidx = 0;
		for(curidx = 0; curidx < results.length; ++curidx)
		{
			if(curidx != 0)
			{
				strbuf.append(",");
				strbuf.append(results[curidx]);
			}
			else
				strbuf.append(results[curidx]);
		}
		retstring = String.format(retstring, strbuf.toString());
		
		return retstring;
		}

}
